﻿#ifndef __AVOID_BW_CONTROL_X_DEFINE_HEAD_FILE_INCLUDED__
#define __AVOID_BW_CONTROL_X_DEFINE_HEAD_FILE_INCLUDED__
#include "../ctlDefine.h"
#include "../edit/caret.h"
#include <windows.h>
#include <GdiPlus.h>
#include <vector>
#include <map>
#include <memory>
#include <ctime>
#include <atomic>

namespace swui
{
	class ctlRoot;
	class ctlStatic;
	class ctlRadioBox;
	class ctlFontQueue;
	class ctlImageQueue;

	//初始化信息
	struct ctlInitInfo
	{
		HWND hWnd;		//[in]
		ctlStatic* root;		//[out]
		bool isUnicode;		//[in]
		ctlInitInfo() : hWnd(0), root(0), 
#ifndef UNICODE
			isUnicode(false)
#else
			isUnicode(true)
#endif
		{}
	};
	
	namespace _ctlInterior
	{
		struct drawInfo
		{
			HDC hDC;
			void* graphics;
			HRGN drawRegion;
		};
		class _ctlRadioSelector
		{
		public:
			unsigned allow()
			{
				unsigned pre = 0;
				for(auto& value : data)
				{
					if(value.first - pre > 1)
						return pre + 1;
					pre = value.first;
				}
				return pre + 1;
			}
			bool isFree(unsigned value)
			{
				return data.count(value) == 0;
			}
		public:
			void push(unsigned group, ctlRadioBox* node)
			{
				data[group].list.push_back(node);
			}
			void pop(unsigned group, ctlRadioBox* node);
			bool select(unsigned group, ctlRadioBox* node);
		private:
			struct stt{
				std::vector<ctlRadioBox*> list;
				ctlRadioBox* selected;
				stt() : selected(nullptr) {}
			};
			std::map<unsigned, stt> data;
		}; 

		template<typename Format>
		struct positionFormat
		{
			Format format;
			float frac;
			int num;
			ctlRoot* relation;
			positionFormat()
				: frac(0.0f),  num(0), relation(nullptr){}
		};

		class compatibleDC
		{
		public:
			HDC GetDC(){return hdc;}
			compatibleDC(int w,int h)
			{
				width=w;
				height=h;
				HDC deskdc=GetWindowDC(GetDesktopWindow());
				hdc=CreateCompatibleDC(deskdc);
				hbit=CreateCompatibleBitmap(deskdc, width, height);
				holdbit=(HBITMAP)SelectObject(hdc, hbit);
				ReleaseDC(GetDesktopWindow(), deskdc);
			}
			~compatibleDC()
			{
				SelectObject(hdc, holdbit);
				DeleteObject(hbit);
				DeleteDC(hdc);
			}
		public:
			HBITMAP hbit, holdbit;
			HDC hdc;
			int width, height;
		};

		struct fixedInfo {
			compatibleDC* tdc;
			Gdiplus::Graphics* graphics;
			fixedInfo() : tdc(0), graphics(0) {}
		};

		class tempAlphaDC
		{
			::std::shared_ptr<compatibleDC> tdc;
			::std::shared_ptr<Gdiplus::Graphics> graphics;
		public:
			tempAlphaDC()
			{
				tdc = ::std::shared_ptr<compatibleDC>(new compatibleDC(1, 1));
			}
		public:
			HDC getDC() { return tdc->GetDC(); }
			Gdiplus::Graphics* getGdip() { return graphics.get(); }
			void require(int cx, int cy) 
			{
				if(cx > tdc->width || cy > tdc->height)
				{
					tdc = ::std::shared_ptr<compatibleDC>(new compatibleDC(cx, cy));
					graphics = ::std::shared_ptr<Gdiplus::Graphics>(new Gdiplus::Graphics(tdc->GetDC()));
					SetBkMode(getDC(), TRANSPARENT);
					graphics->SetSmoothingMode(Gdiplus::SmoothingModeHighQuality);
				}
			}
		};

		struct majorInfo
		{
			bool isRedrawRequired;
			unsigned redrawFrequency;
			HANDLE hRedrawEvent, hExitEvent, hNoDrawingEvent;
			HANDLE hRedrawSenderThread, hRedrawReceiveThread;
			std::clock_t preDrawTime;		// 上一次重绘所消耗的时间

			HWND hWnd;
			ctlRoot* root;
			ctlRoot* focus, *preFocus;
			std::atomic_int drawingCount;	// 即重绘锁计数
			std::atomic_uint notallowedDrawCount;
			ctlRoot* mouseCapture;
			ctlRoot* mouseStay;
			ctlRoot* moveCapture;		// 若不为 nullptr，move 事件全部发送至 moveCapture
			WNDPROC wndProc;
			// 重绘区域
			HRGN redrawRegion;
			// char 转换部分
			bool isUnicode, isDoubleChar;
			char tempchar;
			// GDI 透明绘制的暂存 DC
			tempAlphaDC tempAlpha;
			// 双缓冲DC
			fixedInfo fixedDC;
			// ctlRadioBox 分组
			_ctlRadioSelector radioGroup;
			// 字体队列
			std::shared_ptr<ctlFontQueue>  constantFont;
			//图像队列
			std::shared_ptr<ctlImageQueue> constantImage;
			// 插入符
			caret hCaret;
			// 保存光标句柄
			HCURSOR hCursor;
			bool bindCursor;
			
			class _GraphicsInit
			{
			public:
				_GraphicsInit() {
					Gdiplus::GdiplusStartup(&m_gdiplusToken,&gdiplusStartupInput,0);
				}
				~_GraphicsInit() {
					Gdiplus::GdiplusShutdown(m_gdiplusToken);
				};
				Gdiplus::GdiplusStartupInput gdiplusStartupInput;
				ULONG_PTR m_gdiplusToken;
			} *gdiplusInstance;
		};

		template<typename T, typename paramType>
		struct eventContain
		{
			struct data
			{
				paramType param;
				T value;
				bool enable;
				data(T v, paramType p = 0) : param(p), value(v), enable(true) {}
				bool operator == (T v) { return v == value; }
			};
			eventContain() : isCalling(false) {}
			std::vector<data> contain;
			std::vector<data> tempContain;
			bool isCalling;
		};

	}	//namespace _ctlInterior

}	//namespace swui

#endif